'/*
' * FAHWatch7  Copyright Marvin Westmaas ( mtm )
' *
' * This program is free software; you can redistribute it and/or
' * modify it under the terms of the GNU General Public License
' * as published by the Free Software Foundation; version 2
' * of the License. See the included file GPLv2.TXT.
' * 
' * This program is distributed in the hope that it will be useful,
' * but WITHOUT ANY WARRANTY; without even the implied warranty of
' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' * GNU General Public License for more details.
' * 
' * You should have received a copy of the GNU General Public License
' * along with this program; if not, write to the Free Software
' * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
' */
'/*	
Imports HWInfo.clsHWInfo
Imports gpuInfo.gpuInfo
Imports System.Text
Imports System.IO
Public Class clsLogParser
#Region "Client definition"
    Public Class clsClient
#Region "Object definitions and storage"
        Public ClientName As String = "local"
        Public ClientLocation As String = ""
        Public Enabled As Boolean = True
        Public Sub New(ByVal Name As String, ByVal Location As String)
            ClientName = Name
            ClientLocation = Location
        End Sub
        Public Class clsLogFile
#Region "Slots"
            'Extending logfile structure with log information
            Public Class clsSlots
                Public Class clsSlot
                    Private _ID As String = ""
                    Public ReadOnly Property ID As String
                        Get
                            Return _ID
                        End Get
                    End Property
                    Private _HW As String = ""
                    Public ReadOnly Property HW As String
                        Get
                            Return _HW
                        End Get
                    End Property
                    Private _Status As String = ""
                    Public ReadOnly Property Status As String
                        Get
                            Return _Status
                        End Get
                    End Property
                    Private _current_WU As String = ""
                    Public ReadOnly Property Current_WU As String
                        Get
                            Return _current_WU
                        End Get
                    End Property
                    Private _wu_ID As String = ""
                    Public ReadOnly Property wu_ID As String
                        Get
                            Return _wu_ID
                        End Get
                    End Property
                    'Get detailed status info through wu collection!
                    Public Sub New(ByVal ID As String, ByVal HW As String, Optional ByVal Status As String = "", Optional ByVal Current_WU As String = "", Optional ByVal wu_ID As String = "")
                        _ID = ID : _HW = HW ' Use :%index% to identify hw with same name's
                        _Status = Status : _current_WU = Current_WU : _wu_ID = wu_ID
                    End Sub
                    Public Sub Set_Status(ByVal Status As String)
                        _Status = Status
                    End Sub
                    Public Sub Set_Current_WU(ByVal Current_WU As String, ByVal wu_ID As String)
                        _current_WU = Current_WU : _wu_ID = wu_ID
                    End Sub
                End Class
                Private lstSlots As New Dictionary(Of String, clsSlot)
                Public ReadOnly Property Slots As List(Of clsSlot)
                    Get
                        Return lstSlots.Values.ToList
                    End Get
                End Property
                Public Sub AddSlot(ByVal Slot As clsSlot)
                    Try
                        If Not lstSlots.ContainsKey(Slot.ID & ";" & Slot.HW) Then
                            lstSlots.Add(Slot.ID & ";" & Slot.HW, Slot)
                        End If
                    Catch ex As Exception
                        LogWindow.WriteError(ex.Message, Err)
                    End Try
                End Sub
            End Class
#End Region
            'Using file attributes is more efficient then opening the log and then checking properties, will probably do this later 
            Public Class clsWU
                'Line identifier 
                Public lineIndex As Int32 = 0
#Region "FrameInfo"
                Public Class clsFrame
                    Private dtFrame As DateTime
                    Private strFrame As String
                    Public Sub New(ByVal Line As String, ByVal FrameDT As DateTime)
                        strFrame = Line
                        dtFrame = FrameDT
                    End Sub
                    Public ReadOnly Property LogString As String
                        Get
                            Return strFrame
                        End Get
                    End Property
                    Public ReadOnly Property strPercentage As String
                        Get
                            Dim rVal As String = ""
                            For xIP As Int32 = strFrame.IndexOf("%") To 1 Step -1
                                If strFrame.Substring(xIP, 1) = " " Or strFrame.Substring(xIP, 1) = "(" Then
                                    rVal = strFrame.Substring(xIP, strFrame.IndexOf("%") - xIP).Trim.Replace("(", "").Trim
                                    Exit For
                                End If
                            Next
                            Return rVal
                        End Get
                    End Property
                    Public ReadOnly Property Percentage As Short
                        Get
                            Return CShort(strPercentage)
                        End Get
                    End Property
                    Public ReadOnly Property FrameDT As DateTime
                        Get
                            Return dtFrame
                        End Get
                    End Property
                End Class
                Private lstFrames As New Dictionary(Of String, clsFrame)
                Public Sub AddFrame(ByVal Frame As String, ByVal dtFrame As DateTime)
                    If Not lstFrames.Keys.Contains(Frame) Then
                        'Add the frame
                        Dim nFrame As New clsFrame(Frame, dtFrame)
                        lstFrames.Add(Frame, nFrame)
                    End If
                End Sub
                Public ReadOnly Property Frames As List(Of clsFrame)
                    Get
                        Dim rVal As New List(Of clsFrame)
                        rVal.AddRange(lstFrames.Values)
                        Return rVal
                    End Get
                End Property
                Public Sub ClearFrames()
                    lstFrames.Clear()
                End Sub
#End Region
#Region "Properties"
                Public PRCG As String = ""
                Public ID As String = ""
                Public unit As String = ""
                Public CS As String = ""
                Public WS As String = ""
                Public Slot As String = ""
                Public HW As String = ""
                Public Percentage As String = ""
                Public CoreStatus As String = ""
                Public Credit As String = ""
                Public ServerResponce As String = ""
                Public CoreSnippet As String = ""
                Public CoreVersion As String = ""
                Public CoreCompiler As String = ""
                Public Core As String = ""
                Public BoardType As String = ""
                Public Log As String = ""
                Public dtDownloaded As DateTime
                Public dtStarted As DateTime
                Public dtCompleted As DateTime
                Public dtSubmitted As DateTime
#End Region
#Region "Restarted work unit info"
                Public bHasRestarted As Boolean = False
                Public Class clsRestarted
                    Public Class clsRInfo
                        Private _CoreStatus As String = ""
                        Public ReadOnly Property CoreStatus As String
                            Get
                                Return _CoreStatus
                            End Get
                        End Property
                        Private _LastFrame As clsFrame
                        Public ReadOnly Property LastFrame As clsFrame
                            Get
                                Return _LastFrame
                            End Get
                        End Property
                        Public Sub New(ByVal CoreStatus As String, ByVal Frame As clsFrame)
                            _CoreStatus = CoreStatus : _LastFrame = Frame
                        End Sub
                    End Class
                    Private _lstrInfo As New Dictionary(Of DateTime, clsRInfo)
                    Public ReadOnly Property RestartInfo As List(Of clsRInfo)
                        Get
                            Return _lstrInfo.Values.ToList
                        End Get
                    End Property
                    Public Sub AddRestart(ByVal CoreStatus As String, ByVal Frame As clsFrame)
                        Try
                            If Not _lstrInfo.ContainsKey(Frame.FrameDT) Then
                                _lstrInfo.Add(Frame.FrameDT, New clsRInfo(CoreStatus, Frame))
                            End If
                        Catch ex As Exception
                            LogWindow.WriteError(ex.Message, Err)
                        End Try
                    End Sub

                End Class
                Public restartInfo As New clsRestarted
#End Region
#Region "Work unit Report"
                Public ReadOnly Property Report As String
                    Get
                        Dim sb As New StringBuilder
                        sb.AppendLine("PRCG: " & PRCG)
                        sb.AppendLine("unit: " & unit)
                        sb.AppendLine("ID: " & ID)
                        sb.AppendLine("Slot: " & Slot)
                        sb.AppendLine("Hardware: " & HW)
                        sb.AppendLine("Core: " & Core)
                        sb.AppendLine("Compiler: " & CoreCompiler)
                        sb.AppendLine("BoardType: " & BoardType)
                        sb.AppendLine("Downloaded: " & dtDownloaded.ToString)
                        sb.AppendLine("Completed: " & dtCompleted.ToString)
                        sb.AppendLine("Corestatus: " & CoreStatus)
                        sb.AppendLine("Has restarted: " & bHasRestarted.ToString)
                        sb.AppendLine("Submitted: " & dtSubmitted.ToString)
                        sb.AppendLine("ServerResponce: " & ServerResponce)
                        sb.AppendLine("Credit: " & Credit)
                        sb.AppendLine("WorkServer: " & WS)
                        sb.AppendLine("CollectionServer: " & CS) 'Not enough log info yet to parse the collection servers
                        Return sb.ToString
                    End Get
                End Property
#End Region
            End Class
            Public dWU As New Dictionary(Of String, clsWU)
            Public ReadOnly Property lstWU As List(Of clsWU)
                Get
                    Return dWU.Values.ToList
                End Get
            End Property
            Public ClientInfo As New clsClientInfo.Info
            Public ClientConfig As New clsClientConfig.clsConfiguration
            Public Diagnostic As String = ""
            Public Log As String = ""
            Public File As String = ""
            Public LineCount As String = ""
            Public ReadOnly Property logDate As DateTime
                Get
                    Try
                        Return DateTime.Parse(Log.Replace("*", "").Replace("Log Started", "").Trim.Replace("-", " "))
                    Catch ex As Exception
                        Return New DateTime
                    End Try
                End Get
            End Property
        End Class
        Public dLogFiles As New Dictionary(Of String, clsLogFile)
        Public ReadOnly Property lstLogFiles As List(Of clsLogFile)
            Get
                Return dLogFiles.Values.ToList
            End Get
        End Property
        Public ReadOnly Property ActiveLog As clsLogFile
            Get
                If lstLogFiles.Count = 0 Then
                    Return Nothing
                Else
                    Return lstLogFiles(lstLogFiles.Count - 1)
                End If
            End Get
        End Property
#End Region
#Region "Parsing"
        Public Function ParseLogs(Optional ByVal ShowUI As Boolean = False, Optional ByVal Location As String = "") As Boolean
            'Ideally parselogs should support only parsing active log 
            Try
                Dim nFiles As New List(Of String)
                If Location = "" And ClientLocation = "" Then
                    Dim lLoc As String = ClientConfig.Configuration.DataLocation & "\Logs\"
                    Dim lFiles = My.Computer.FileSystem.GetFiles(lLoc, FileIO.SearchOption.SearchTopLevelOnly, "log*.txt")
                    nFiles.AddRange(lFiles)
                    nFiles.Add(ClientConfig.Configuration.DataLocation & "\log.txt")
                ElseIf Location = "" And ClientLocation <> "" Then
                    Dim lLoc As String = ClientLocation & "\Logs\"
                    Dim lFiles = My.Computer.FileSystem.GetFiles(lLoc, FileIO.SearchOption.SearchTopLevelOnly, "log*.txt")
                    nFiles.AddRange(lFiles)
                    nFiles.Add(ClientLocation & "\log.txt")
                Else
                    Dim lLoc As String = Location & "\Logs\"
                    Dim lFiles = My.Computer.FileSystem.GetFiles(lLoc, FileIO.SearchOption.SearchTopLevelOnly, "log*.txt")
                    nFiles.AddRange(lFiles)
                    nFiles.Add(Location & "\log.txt")
                End If
                'If Location = "" Then
                '    Dim lLoc As String = ClientConfig.Configuration.DataLocation & "\Logs\"
                '    Dim lFiles = My.Computer.FileSystem.GetFiles(lLoc, FileIO.SearchOption.SearchTopLevelOnly, "log*.txt")
                '    nFiles.AddRange(lFiles)
                '    nFiles.Add(ClientConfig.Configuration.DataLocation & "\log.txt")
                'Else
                '    Dim lLoc As String = Location & "\Logs\"
                '    Dim lFiles = My.Computer.FileSystem.GetFiles(lLoc, FileIO.SearchOption.SearchTopLevelOnly, "log*.txt")
                '    nFiles.AddRange(lFiles)
                '    nFiles.Add(Location & "\log.txt")
                'End If
                'Declare combined log object
                Dim comLog As New List(Of String)
                Try
                    Dim iFile As Int32 = 1 'Index of log file 
                    Dim iLog As Int32 = 0 'Index of current line in log
                    Dim iSkipLog As Int32 = -1 'Next line with unit request 
                    'Main file loop
                    Do
                        Dim nLOG As New clsLogFile
                        nLOG.File = nFiles(iFile - 1)
                        Dim lText As String = ""
                        Try
                            lText = My.Computer.FileSystem.ReadAllText(nFiles(iFile - 1))
                        Catch ex As Exception
                            Dim fStream As FileStream = New FileStream(nFiles(iFile - 1), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024, System.IO.FileOptions.Asynchronous)
                            Dim fRead As StreamReader = New StreamReader(fStream)
                            lText = fRead.ReadToEnd
                            fRead.Close()
                            fStream.Close()
                            fRead = Nothing
                            fStream = Nothing
                        End Try
                        Dim lLines() = lText.Split(Environment.NewLine)
                        Dim iAddDays As Int16 = 0
                        'Copy log section
                        comLog.AddRange(lLines)
                        nLOG.LineCount = lLines.Count
                        nLOG.Log = lText.Substring(0, lText.IndexOf(Environment.NewLine))
                        Try
                            If Me.lstLogFiles(iFile - 1).File = nLOG.File And Me.lstLogFiles(iFile - 1).LineCount = nLOG.LineCount Then
                                ' Verify!!
                                GoTo SkipFile
                            End If
                        Catch ex As Exception

                        End Try
                        If lText.Contains("********************** Folding@home Client *************************") And lText.Contains("********************************************************************") Then
                            Dim strInfo As String = lText.Substring(lText.IndexOf("********************** Folding@home Client *************************"), lText.LastIndexOf("********************************************************************") - lText.IndexOf("********************** Folding@home Client *************************"))
                            Dim sb As New StringBuilder
                            For Each Line As String In strInfo.Split(Environment.NewLine)
                                If Line.Contains(":") Then
                                    sb.AppendLine(Line.Substring(10))
                                Else
                                    sb.AppendLine(Line)
                                End If
                            Next
                            strInfo = sb.ToString
                            nLOG.ClientInfo.ParseString(strInfo)
                        End If
                        If lText.Contains("<config>") AndAlso lText.Contains("</config>") Then
                            Dim strConfig As String = lText.Substring(lText.IndexOf("<config>"), lText.IndexOf(Environment.NewLine, lText.IndexOf("</config>")) - lText.IndexOf("<config>"))
                            Dim sb As New StringBuilder
                            For Each Line As String In strConfig.Split(Environment.NewLine)
                                If Line.Contains(":") Then
                                    sb.AppendLine(Line.Substring(10))
                                Else
                                    sb.AppendLine(Line)
                                End If
                            Next
                            strConfig = sb.ToString
                            nLOG.ClientConfig.ReadString(strConfig)
                        End If

                        'Main line loop
                        iLog = 0

                        Do
                            Dim Line As String = ""
                            Line = lLines(iLog).Trim.Replace(ChrW(10), "")
                            If iLog - 1 > 0 And Line.Length > 2 AndAlso lLines(iLog - 1).Length > 2 Then
                                Try
                                    If CInt(lLines(iLog - 1).Replace(ChrW(34), "").Replace(ChrW(10), "").Trim.Substring(0, 2)) > CInt(lLines(iLog).Replace(ChrW(34), "").Replace(ChrW(10), "").Trim.Substring(0, 2)) Then
                                        iAddDays += 1
                                    End If
                                Catch ex As Exception : End Try
                            End If
                            If Line.Contains("Received Unit: ") Then
                                'Start parsing all info for this work unit
                                Dim nWU As New clsLogFile.clsWU
                                nWU.lineIndex = iLog
                                nWU.Log = nLOG.Log
                                nWU.ID = Line.Substring(Line.IndexOf("id:") + 3, Line.IndexOf("state:") - (Line.IndexOf("id:") + 3)).Trim
                                nWU.unit = Line.Substring(Line.IndexOf("unit:") + 5).Trim
                                nWU.PRCG = Line.Substring(Line.IndexOf("project:"), Line.IndexOf("core:") - (Line.IndexOf("project:"))).Trim
                                nWU.Core = Line.Substring(Line.IndexOf("core:") + 5, 4).Trim
                                'fill wu info, scan lines upwards for 'Download complete'
                                For xInt As Int32 = iLog To 0 Step -1
                                    If lLines(xInt).Contains("Download complete") And nWU.Slot = "" Then
                                        nWU.Slot = lLines(xInt).Substring(15, 2)
                                        nWU.dtDownloaded = nLOG.logDate.Date.AddDays(iAddDays).Add(TimeSpan.Parse(lLines(xInt).Trim.Replace(ChrW(10), "").Substring(0, 8)))
                                    ElseIf lLines(xInt).Contains("Requesting new work unit for slot ") Then
                                        If lLines(xInt).Contains(Chr(34)) Then
                                            nWU.HW = lLines(xInt).Substring(lLines(xInt).IndexOf(ChrW(34)) + 1, lLines(xInt).LastIndexOf(ChrW(34)) - lLines(xInt).IndexOf(ChrW(34)) - 1)
                                        Else
                                            If lLines(xInt).Contains("READY") Then
                                                nWU.HW = lLines(xInt).Substring(lLines(xInt).IndexOf("READY") + 6, lLines(xInt).IndexOf("from") - (lLines(xInt).IndexOf("READY") + 8))
                                            ElseIf lLines(xInt).Contains("PAUSED") Then
                                                nWU.HW = lLines(xInt).Substring(lLines(xInt).IndexOf("PAUSED") + 7, lLines(xInt).IndexOf("from") - (lLines(xInt).IndexOf("PAUSED") + 8))
                                            ElseIf lLines(xInt).Contains("RUNNING") Then
                                                nWU.HW = lLines(xInt).Substring(lLines(xInt).IndexOf("RUNNING") + 8, lLines(xInt).IndexOf("from") - (lLines(xInt).IndexOf("RUNNING") + 8))
                                            End If
                                        End If
                                    ElseIf nWU.WS = "" AndAlso lLines(xInt).Contains("Assigned to work server ") Then
                                        nWU.WS = lLines(xInt).Substring(lLines(xInt).IndexOf("Assigned to work server ") + Len("assigned to work server")).Trim
                                        Exit For
                                    End If
                                Next
                                If Not nLOG.dWU.ContainsKey(nWU.unit) Then
                                    nLOG.dWU.Add(nWU.unit, nWU)
                                End If
                            End If
StageTwo:
                            'Increase line pointer
                            'iLog += 1
                            If iSkipLog = -1 Then
                                iLog += 1
                            Else
                                'DebugOut.WriteLog("Skipping to line: " & iSkipLog)
                                iLog = iSkipLog
                                iSkipLog = -1
                            End If
                            'Application.DoEvents()
                            '/Main line loop
                        Loop While iLog < lLines.Count - 1
                        'Add the log section 
                        If Not dLogFiles.ContainsKey(nLOG.Log.Replace("*", "").Trim) Then
                            dLogFiles.Add(nLOG.Log.Replace("*", "").Trim, nLOG)
                        End If
                        'Increase file pointer
SkipFile:
                        iFile += 1
                        '/Main file loop
                    Loop While iFile <= nFiles.Count
                    ' Parse unit's
                    Dim iLogStartIndex As Int32 = 0
                    For xLSection As Int32 = 0 To Me.lstLogFiles.Count - 1
                        Dim currentSection As clsLogFile = Me.lstLogFiles(xLSection)
                        'Get startindex for comLog
                        If xLSection > 0 Then iLogStartIndex += Me.lstLogFiles(xLSection - 1).LineCount
                        For Each nWU As clsLogFile.clsWU In currentSection.lstWU
                            If nWU.CoreStatus <> "" Then
                                GoTo SkipWU
                            End If
                            'Remove!
                            'If nWU.PRCG = "project:6806 run:8220 clone:2 gen:7" Then
                            '    Debug.WriteLine(DateTime.Now.ToString(strDTFormat) & " " & nWU.PRCG & " parsing started")
                            'End If
                            'Remove'
                            'Verify starting line
                            If comLog(nWU.lineIndex + iLogStartIndex).Contains(nWU.unit) Then
                                'Parse the unit, use dtDownloaded as starting dt increment with iAddDays
                                Dim iAddDays As Int16 = 0, dtStart As DateTime = nWU.dtDownloaded
                                For xInt As Int32 = nWU.lineIndex + iLogStartIndex To comLog.Count - 1
                                    'Remove!
                                    'If nWU.PRCG = "project:6806 run:8220 clone:2 gen:7" Then
                                    '    Debug.WriteLine(comLog(xInt))
                                    'End If
                                    'Remove!
                                    If comLog(xInt).Contains(" Log Started ") Then
                                        'Set new starting datetime, reset iAddDays
                                        dtStart = DateTime.Parse(comLog(xInt).Replace("*", "").Replace("Log Started", "").Trim.Replace("-", " "))
                                        iAddDays = 0
                                    End If
                                    Try
                                        If CInt(comLog(xInt - 1).Replace(ChrW(34), "").Replace(ChrW(10), "").Trim.Substring(0, 2)) > CInt(comLog(xInt).Replace(ChrW(34), "").Replace(ChrW(10), "").Trim.Substring(0, 2)) Then
                                            iAddDays += 1
                                        End If
                                    Catch ex As Exception : End Try
                                    'Unit properties
                                    If nWU.dtStarted = #1/1/2000# AndAlso comLog(xInt).Contains(("Starting Unit " & nWU.ID).ToString) Then
                                        nWU.dtStarted = dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Trim.Replace(ChrW(10), "").Substring(0, 8)))
                                    End If
                                    If nWU.CoreVersion = "" AndAlso comLog(xInt).Contains("Unit " & nWU.ID & ":Version ") Then
                                        nWU.CoreVersion = comLog(xInt).Substring(comLog(xInt).IndexOf("Version ") + 8).Trim
                                    End If
                                    If nWU.CoreCompiler = "" AndAlso comLog(xInt).Contains("Unit " & nWU.ID & ":Compiler ") Then
                                        nWU.CoreCompiler = comLog(xInt).Substring(comLog(xInt).IndexOf("Compiler ") + 10).Trim
                                    End If
                                    If nWU.BoardType = "" AndAlso comLog(xInt).Contains("Unit " & nWU.ID & ":Board Type:") Then
                                        nWU.BoardType = comLog(xInt).Substring(comLog(xInt).IndexOf("Board Type:") + 11).Trim
                                    End If
                                    If comLog(xInt).Contains("Unit " & nWU.ID & ":") And comLog(xInt).Contains("%") Then
                                        For xIP As Int32 = comLog(xInt).IndexOf("%") To 1 Step -1
                                            If comLog(xInt).Substring(xIP, 1) = " " Or comLog(xInt).Substring(xIP, 1) = "(" Then
                                                nWU.Percentage = comLog(xInt).Substring(xIP, comLog(xInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim
                                                nWU.AddFrame(comLog(xInt), dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Trim.Replace(ChrW(10), "").Substring(0, 8))))
                                                Exit For
                                            End If
                                        Next
                                    End If
                                    'Unit completion - corestatus - submitted - snippet
                                    If comLog(xInt).Contains("FahCore, running Unit " & nWU.ID & ", returned:") Or comLog(xInt).Contains("FahCore running Unit " & nWU.ID & " returned:") Then
                                        'Skipping CoreOutdated message.
                                        If comLog(xInt).Substring(comLog(xInt).IndexOf("returned:") + 10).Contains("110") Then
                                            'Check if core is downloaded, what happens when the core can't be downloaded, does the client dump the unit and continue with a new one?
                                            GoTo Skip 'seems to work if the result is either a 'failing' or 'dumping' message in the end
                                        ElseIf Not comLog(xInt).Substring(comLog(xInt).IndexOf("returned:") + 10).Contains("100") Then
                                            'Check for 'failing' or 'starting'
                                            For yInt As Int32 = xInt + 1 To comLog.Count - 1
                                                If comLog(yInt).Contains("Unit " & nWU.ID) Then
                                                    If comLog(yInt).ToUpper.Contains("FAILING") Then
                                                        'Remove!
                                                        'If nWU.PRCG = "project:6806 run:8220 clone:2 gen:7" Then
                                                        '    Debug.WriteLine("FAILED!")
                                                        'End If
                                                        'Remove!
                                                        'Unit will be dumped accept core status ect
                                                        Exit For
                                                    ElseIf comLog(yInt).ToUpper.Contains("STARTING") Then
                                                        'Set wu property indicating restart
                                                        nWU.bHasRestarted = True
                                                        'Add restart info
                                                        nWU.restartInfo.AddRestart(nWU.CoreStatus, nWU.Frames(nWU.Frames.Count - 1))
                                                        'Check to clear frames!
                                                        For zInt As Int32 = yInt To comLog.Count - 1
                                                            If comLog(zInt).Contains("Unit " & nWU.ID & ":") And comLog(zInt).Contains("%") Then
                                                                For xIP As Int32 = comLog(zInt).IndexOf("%") To 1 Step -1
                                                                    If comLog(zInt).Substring(xIP, 1) = " " Or comLog(zInt).Substring(xIP, 1) = "(" Then
                                                                        If comLog(zInt).Substring(xIP, comLog(zInt).IndexOf("%") - xIP).Trim.Replace("(", "").Trim < nWU.Percentage Then
                                                                            nWU.ClearFrames()
                                                                            GoTo FramesCleared
                                                                        Else
                                                                            GoTo FramesCleared
                                                                        End If
                                                                    End If
                                                                Next
                                                            End If
                                                        Next
FramesCleared:

                                                        'Exit core status code
                                                        GoTo Skip
                                                    End If
                                                End If
                                            Next
                                        End If
                                        nWU.CoreStatus = comLog(xInt).Substring(comLog(xInt).IndexOf("returned:") + 10)
                                        nWU.dtCompleted = dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(xInt).Trim.Replace(ChrW(10), "").Substring(0, 8)))
                                        'Get size of submission snippet
                                        Dim iStart As Int32 = -1, iEnd As Int32 = -1
                                        'iStart
                                        For zInt As Int32 = xInt To xInt - 50 Step -1
                                            If zInt = 0 Then
                                                iStart = 0
                                                Exit For
                                            End If
                                            If (comLog(zInt).Contains("Unit " & nWU.ID & ":") And comLog(zInt).Contains("%")) Or comLog(zInt).ToUpper.Contains("UNIT " & nWU.ID & ":ENTERING") Then
                                                iStart = zInt
                                                Exit For
                                            End If
                                        Next
                                        If iStart = -1 Then iStart = xInt - 50 'Set iStart to -50 if previous loop was unsuccesfull 
                                        'iEnd 
                                        For yInt As Int32 = xInt To comLog.Count - 1
                                            If comLog(yInt).Contains(" Log Started ") Then
                                                'Set new starting datetime, reset iAddDays
                                                dtStart = DateTime.Parse(comLog(yInt).Replace("*", "").Replace("Log Started", "").Trim.Replace("-", " "))
                                                iAddDays = 0
                                            End If
                                            Try
                                                If CInt(comLog(yInt - 1).Replace(ChrW(34), "").Replace(ChrW(10), "").Trim.Substring(0, 2)) > CInt(comLog(yInt).Replace(ChrW(34), "").Replace(ChrW(10), "").Trim.Substring(0, 2)) Then
                                                    iAddDays += 1
                                                End If
                                            Catch ex As Exception : End Try
                                            'If (comLog(yInt).Contains("Unit " & nWU.ID & ": Upload complete")) Or (comLog(yInt).Contains("Unit " & nWU.ID & " Fatal error, dumping")) Or comLog(yInt).Contains("Cleaning Up Unit " & nWU.ID) Then
                                            If (comLog(yInt).Contains("Unit " & nWU.ID) And comLog(yInt).Contains("Cleaning up")) Or (comLog(yInt).Contains("Unit " & nWU.ID) And comLog(yInt).Contains("Fatal error, dumping")) Then
                                                For zInt As Int32 = yInt - 1 To 0 Step -1
                                                    If comLog(zInt).Contains("Unit " & nWU.ID) Then
                                                        'Exit this loop
                                                        Exit For
                                                    End If
                                                    If comLog(zInt).Contains("Server responded ") Then
                                                        'Add server responce to wu object 
                                                        nWU.ServerResponce = comLog(zInt).Trim(Chr(10)).Substring(26)
                                                    End If
                                                    If comLog(zInt).Contains("Final credit estimate, ") Then
                                                        'Add credit field to wu object
                                                        nWU.Credit = CInt(comLog(zInt).Trim(Chr(10)).Substring(32).Replace(" points", "")).ToString 'Loose decimals?
                                                    End If
                                                Next
                                                nWU.dtSubmitted = dtStart.Date.AddDays(iAddDays).Add(TimeSpan.Parse(comLog(yInt).Trim.Replace(ChrW(10), "").Substring(0, 8)))
                                                iEnd = yInt
                                                Exit For
                                            End If
                                        Next
                                        If iEnd = -1 Then iEnd = xInt + 10 'Set iEnd to +10 if previous loop was not succesfull
                                        Dim sb2 As New StringBuilder
                                        For hInt As Int32 = iStart To iEnd
                                            sb2.AppendLine(comLog(hInt).Replace(ChrW(10), ""))
                                        Next
                                        nWU.CoreSnippet = sb2.ToString.Trim
                                        'update lstWU
                                        Exit For
Skip:
                                    End If
                                    '/xInt
                                Next
                            End If
                            '/nWu
SkipWU:
                        Next
                        '/lSection
                    Next
                Catch ex As Exception
                    'LogWindow.WriteError(ex.Message, Err)
                    'Return False
                End Try
                Return True
            Catch ex As Exception
                LogWindow.WriteError(ex.Message, Err)
                Return False
            End Try
        End Function
#End Region
#Region "Instance Report"
        Public Structure sClientStatistics
            Public WU_Completed As String
            Public WU_EUE As String
            Public SuccesRate As String
            Public ComputationTime As String
            Public WaitingTime As String
            Public TotalCredit As String
            Public AveragePPD As String
        End Structure
        Public ReadOnly Property Statistics As sClientStatistics
            Get
                Dim rV As New sClientStatistics
                Try
                    Dim iWU_total As Int32 = 0
                    Dim iWU_EUE As Int32 = 0
                    Dim tsProcessing As New TimeSpan
                    Dim tsWaitingToUpload As New TimeSpan
                    Dim iTotalCredit As Int32 = 0
                    For Each lSec As clsLogFile In Me.lstLogFiles
                        For Each lWU As clsLogFile.clsWU In lSec.lstWU
                            iWU_total += 1
                            'Debug.WriteLine(lWU.PRCG)
                            If lWU.CoreStatus <> "" Then
                                If Not lWU.CoreStatus.Contains("(100)") And Not lWU.CoreStatus.Contains("(100 = 0x64)") Then iWU_EUE += 1
                                ' WaitingToUpload is not incrementd with unit's which don't have any frames ( though, should it be counted for partial results which do generate some credit.. )
                                If lWU.Frames.Count > 0 Then
                                    tsProcessing = tsProcessing.Add(lWU.Frames(lWU.Frames.Count - 1).FrameDT - lWU.Frames(0).FrameDT)
                                    tsWaitingToUpload = tsWaitingToUpload.Add(lWU.dtSubmitted.Subtract(lWU.Frames(lWU.Frames.Count - 1).FrameDT))
                                End If
                                If lWU.dtSubmitted <> #1/1/2000# And lWU.ServerResponce.Contains("(400)") Then
                                    If lWU.Credit = "" Then
                                        If projectInfo.Projects.KnownProject(lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))) Then
                                            iTotalCredit += CInt(projectInfo.GetEffectivePPD_sqrt(lWU.dtDownloaded, lWU.dtSubmitted, lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))).Credit)
                                        End If
                                    Else
                                        'Code duplication :(
                                        Dim tsP As TimeSpan = lWU.dtSubmitted.Subtract(lWU.dtDownloaded)
                                        Dim iPworth As Integer = CInt(lWU.Credit)
                                        Dim iPPD As Double = 0
                                        Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                                        Do
                                            If tsDay.Subtract(tsP).TotalSeconds >= 0 Then
                                                iPPD += iPworth
                                                tsDay = tsDay.Subtract(tsP)
                                            Else
                                                Exit Do
                                            End If
                                        Loop
                                        'get fraction of _tsFrame to be done in remaining seconds
                                        Dim iRfraction As Double
                                        If tsDay.TotalSeconds > 0 Then
                                            iRfraction = tsDay.TotalSeconds / tsP.TotalSeconds
                                            iPPD += iRfraction * iPworth
                                        End If
                                        iTotalCredit += Math.Round(iPPD, 2)
                                    End If
                                End If
                            End If
                        Next
                    Next
                    rV.WU_Completed = iWU_total.ToString
                    rV.WU_EUE = iWU_EUE.ToString
                    rV.SuccesRate = 100 - (iWU_EUE / (iWU_total / 100)) & "%"
                    rV.ComputationTime = tsProcessing.ToString
                    rV.WaitingTime = tsWaitingToUpload.ToString 'Should also add timespan between requesting to download and actual download IF the slot is not stil processing the previous work unit
                    rV.TotalCredit = iTotalCredit.ToString
                Catch ex As Exception
                    LogWindow.WriteError(ex.Message, Err)
                End Try
                Return rV
            End Get
        End Property
        Public ReadOnly Property SystemStatistics As String
            Get
                Dim sb As New StringBuilder
                Try
                    Dim iWU_total As Int32 = 0
                    Dim iWU_EUE As Int32 = 0
                    Dim tsProcessing As New TimeSpan
                    Dim tsWaitingToUpload As New TimeSpan
                    Dim iTotalCredit As Int32 = 0
                    For Each lSec As clsLogFile In Me.lstLogFiles
                        For Each lWU As clsLogFile.clsWU In lSec.lstWU
                            iWU_total += 1
                            'Debug.WriteLine(lWU.PRCG)
                            If lWU.CoreStatus <> "" Then
                                If Not lWU.CoreStatus.Contains("(100)") And Not lWU.CoreStatus.Contains("(100 = 0x64)") Then iWU_EUE += 1
                                ' WaitingToUpload is not incrementd with unit's which don't have any frames ....
                                If lWU.Frames.Count > 0 Then
                                    tsProcessing = tsProcessing.Add(lWU.Frames(lWU.Frames.Count - 1).FrameDT - lWU.Frames(0).FrameDT)
                                    tsWaitingToUpload = tsWaitingToUpload.Add(lWU.dtSubmitted.Subtract(lWU.Frames(lWU.Frames.Count - 1).FrameDT))
                                End If
                                If lWU.Percentage = "100" AndAlso projectInfo.Projects.KnownProject(lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))) Then
                                    iTotalCredit += CInt(projectInfo.GetEffectivePPD_sqrt(lWU.dtDownloaded, lWU.dtSubmitted, lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))).Credit)
                                End If
                            End If
                        Next
                    Next
                    sb.AppendLine("Total work units: " & vbTab & iWU_total.ToString)
                    sb.AppendLine("Early Unit Ends: " & vbTab & iWU_EUE.ToString)
                    sb.AppendLine("Succes rate: " & vbTab & vbTab & (100 - (iWU_EUE / (iWU_total / 100))) & "%")
                    sb.AppendLine("Total processing time: " & vbTab & tsProcessing.ToString)
                    'Waiting time counts only upload, adding download can only be done when the slot has no active work unit while waiting for an assignment 
                    sb.AppendLine("Total unit waiting time: " & vbTab & tsWaitingToUpload.ToString)
                    sb.AppendLine("Total credit: " & vbTab & vbTab & iTotalCredit.ToString)
                Catch ex As Exception
                    sb.AppendLine("ERROR: " & ex.Message & " - " & ex.StackTrace.ToString & ex.TargetSite.ToString)
                End Try
                Return sb.ToString
            End Get
        End Property
#End Region
    End Class
#End Region
#Region "Client collection"
    Private _Clients As New Dictionary(Of String, clsClient)
    Public ReadOnly Property Clients As List(Of clsClient)
        Get
            Return _Clients.Values.ToList
        End Get
    End Property
    Public Sub Init(Optional ByVal Name As String = "local")
        Try
            'Add local name support
            _Clients.Add("local", New clsClient(Name, ClientConfig.Configuration.DataLocation))
        Catch ex As Exception
            LogWindow.WriteError(ex.Message, Err)
        End Try
    End Sub
    Public Sub AddClient(ByVal Name As String, ByVal Location As String, Optional ByVal Enabled As Boolean = True)
        Try
            If Not _Clients.ContainsKey(Name) Then
                _Clients.Add(Name, New clsClient(Name, Location))
                _Clients(Name).Enabled = Enabled
            End If
        Catch ex As Exception
            LogWindow.WriteError(ex.Message, Err)
        End Try
    End Sub
    Public ReadOnly Property Client(ByVal Name) As clsClient
        Get
            Return _Clients(Name)
        End Get
    End Property
    Public Sub SetClientState(ByVal Name As String, ByVal State As Boolean)
        Try
            If _Clients.ContainsKey(Name) Then
                _Clients(Name).Enabled = State
            End If
        Catch ex As Exception
            LogWindow.WriteError(ex.Message, Err)
        End Try
    End Sub
    Public Sub RemoveClient(ByVal Name As String)
        Try
            If _Clients.ContainsKey(Name) Then
                _Clients.Remove(Name)
            End If
        Catch ex As Exception
            LogWindow.WriteError(ex.Message, Err)
        End Try
    End Sub
#End Region
#Region "Combined Report"
    Public Structure sClientStatistics
        Public WU_Completed As String
        Public WU_EUE As String
        Public SuccesRate As String
        Public ComputationTime As String
        Public WaitingTime As String
        Public TotalCredit As String
        Public AveragePPD As String
    End Structure
    Public ReadOnly Property Statistics As sClientStatistics
        Get
            Dim rV As New sClientStatistics
            Try
                Dim iWU_total As Int32 = 0
                Dim iWU_EUE As Int32 = 0
                Dim tsProcessing As New TimeSpan
                Dim tsWaitingToUpload As New TimeSpan
                Dim iTotalCredit As Int32 = 0
                For Each Client As clsClient In Me.Clients
                    For Each lSec As clsClient.clsLogFile In Client.lstLogFiles
                        For Each lWU As clsClient.clsLogFile.clsWU In lSec.lstWU
                            iWU_total += 1
                            'Debug.WriteLine(lWU.PRCG)
                            If lWU.CoreStatus <> "" Then
                                If Not lWU.CoreStatus.Contains("(100)") And Not lWU.CoreStatus.Contains("(100 = 0x64)") Then iWU_EUE += 1
                                ' WaitingToUpload is not incrementd with unit's which don't have any frames ( though, should it be counted for partial results which do generate some credit.. )
                                If lWU.Frames.Count > 0 Then
                                    tsProcessing = tsProcessing.Add(lWU.Frames(lWU.Frames.Count - 1).FrameDT - lWU.Frames(0).FrameDT)
                                    tsWaitingToUpload = tsWaitingToUpload.Add(lWU.dtSubmitted.Subtract(lWU.Frames(lWU.Frames.Count - 1).FrameDT))
                                End If
                                If lWU.dtSubmitted <> #1/1/2000# And lWU.ServerResponce.Contains("(400)") Then
                                    If lWU.Credit = "" Then
                                        If projectInfo.Projects.KnownProject(lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))) Then
                                            iTotalCredit += CInt(projectInfo.GetEffectivePPD_sqrt(lWU.dtDownloaded, lWU.dtSubmitted, lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))).Credit)
                                        End If
                                    Else
                                        'Code duplication :(
                                        Dim tsP As TimeSpan = lWU.dtSubmitted.Subtract(lWU.dtDownloaded)
                                        Dim iPworth As Integer = CInt(lWU.Credit)
                                        Dim iPPD As Double = 0
                                        Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                                        Do
                                            If tsDay.Subtract(tsP).TotalSeconds >= 0 Then
                                                iPPD += iPworth
                                                tsDay = tsDay.Subtract(tsP)
                                            Else
                                                Exit Do
                                            End If
                                        Loop
                                        'get fraction of _tsFrame to be done in remaining seconds
                                        Dim iRfraction As Double
                                        If tsDay.TotalSeconds > 0 Then
                                            iRfraction = tsDay.TotalSeconds / tsP.TotalSeconds
                                            iPPD += iRfraction * iPworth
                                        End If
                                        iTotalCredit += Math.Round(iPPD, 2)
                                    End If
                                End If
                            End If
                        Next
                    Next
                Next
                rV.WU_Completed = iWU_total.ToString
                rV.WU_EUE = iWU_EUE.ToString
                rV.SuccesRate = 100 - (iWU_EUE / (iWU_total / 100)) & "%"
                rV.ComputationTime = tsProcessing.ToString
                rV.WaitingTime = tsWaitingToUpload.ToString 'Should also add timespan between requesting to download and actual download IF the slot is not stil processing the previous work unit
                rV.TotalCredit = iTotalCredit.ToString
            Catch ex As Exception
                LogWindow.WriteError(ex.Message, Err)
            End Try
            Return rV
        End Get
    End Property
    Public ReadOnly Property SystemStatistics As String
        Get
            Dim sb As New StringBuilder
            Try
                Dim iWU_total As Int32 = 0
                Dim iWU_EUE As Int32 = 0
                Dim tsProcessing As New TimeSpan
                Dim tsWaitingToUpload As New TimeSpan
                Dim iTotalCredit As Int32 = 0
                For Each Client As clsClient In Me.Clients
                    For Each lSec As clsClient.clsLogFile In Client.lstLogFiles
                        For Each lWU As clsClient.clsLogFile.clsWU In lSec.lstWU
                            iWU_total += 1
                            'Debug.WriteLine(lWU.PRCG)
                            If lWU.CoreStatus <> "" Then
                                If Not lWU.CoreStatus.Contains("(100)") And Not lWU.CoreStatus.Contains("(100 = 0x64)") Then iWU_EUE += 1
                                ' WaitingToUpload is not incrementd with unit's which don't have any frames ( though, should it be counted for partial results which do generate some credit.. )
                                If lWU.Frames.Count > 0 Then
                                    tsProcessing = tsProcessing.Add(lWU.Frames(lWU.Frames.Count - 1).FrameDT - lWU.Frames(0).FrameDT)
                                    tsWaitingToUpload = tsWaitingToUpload.Add(lWU.dtSubmitted.Subtract(lWU.Frames(lWU.Frames.Count - 1).FrameDT))
                                End If
                                If lWU.dtSubmitted <> #1/1/2000# And lWU.ServerResponce.Contains("(400)") Then
                                    If lWU.Credit = "" Then
                                        If projectInfo.Projects.KnownProject(lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))) Then
                                            iTotalCredit += CInt(projectInfo.GetEffectivePPD_sqrt(lWU.dtDownloaded, lWU.dtSubmitted, lWU.PRCG.Substring(Len("project:"), lWU.PRCG.IndexOf(" ") - Len("project:"))).Credit)
                                        End If
                                    Else
                                        'Code duplication :(
                                        Dim tsP As TimeSpan = lWU.dtSubmitted.Subtract(lWU.dtDownloaded)
                                        Dim iPworth As Integer = CInt(lWU.Credit)
                                        Dim iPPD As Double = 0
                                        Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                                        Do
                                            If tsDay.Subtract(tsP).TotalSeconds >= 0 Then
                                                iPPD += iPworth
                                                tsDay = tsDay.Subtract(tsP)
                                            Else
                                                Exit Do
                                            End If
                                        Loop
                                        'get fraction of _tsFrame to be done in remaining seconds
                                        Dim iRfraction As Double
                                        If tsDay.TotalSeconds > 0 Then
                                            iRfraction = tsDay.TotalSeconds / tsP.TotalSeconds
                                            iPPD += iRfraction * iPworth
                                        End If
                                        iTotalCredit += Math.Round(iPPD, 2)
                                    End If
                                End If
                            End If
                        Next
                    Next
                Next
                sb.AppendLine("Total work units: " & vbTab & iWU_total.ToString)
                sb.AppendLine("Early Unit Ends: " & vbTab & iWU_EUE.ToString)
                sb.AppendLine("Succes rate: " & vbTab & vbTab & (100 - (iWU_EUE / (iWU_total / 100))) & "%")
                sb.AppendLine("Total processing time: " & vbTab & tsProcessing.ToString)
                'Waiting time counts only upload, adding download can only be done when the slot has no active work unit while waiting for an assignment 
                sb.AppendLine("Total unit waiting time: " & vbTab & tsWaitingToUpload.ToString)
                sb.AppendLine("Total credit: " & vbTab & vbTab & iTotalCredit.ToString)
            Catch ex As Exception
                sb.AppendLine("ERROR: " & ex.Message & " - " & ex.StackTrace.ToString & ex.TargetSite.ToString)
            End Try
            Return sb.ToString
        End Get
    End Property
#End Region
#Region "Functions"
    Public Function ParseLogs() As Boolean
        Try
            For Each Client As clsClient In Clients
                Client.ParseLogs()
            Next
            Return True
        Catch ex As Exception
            LogWindow.WriteError(ex.Message, Err)
            Return False
        End Try
    End Function
#End Region
End Class